/*
 * @version: 1.0
 * @Author: zhl
 * @Date: 2021-09-02 15:49:26
 * @LastEditors: zhanggq
 * @LastEditTime: 2023-11-27 14:57:58
 * @Description: 定时器管理，此处可优化
 */
#include <unordered_map>


#include "HandleThreadManager.h"
#include "TaskManager.h"
#include "CLogger.h"
#include "common.h"
#include "CReportManager.h"


using namespace std;



#define TASK_PARAMS_INIT(DEV_ID,TASK_ID,REQ_ID,PRIORITY,DEV,TOPIC,TYPE,CMD_SRC,ITEMS) TASK_PARAMS param;\
        {                                       \
            param.dev_id    = DEV_ID;           \
            param.task_id   = TASK_ID;          \
            param.req_id    = REQ_ID;           \
            param.type      = TYPE;             \
            param.dev       = DEV;              \
            param.priority  = PRIORITY;         \
            param.topic     = TOPIC;            \
            param.cmd_source= CMD_SRC;          \
            param.items.swap(ITEMS);            \
        } 


typedef void (*TFUNCTION_FINISH)();


TaskManager::TaskManager(){
    c_is_run = true;

    c_is_change_uart_mode = false;
    c_tasks = std::make_shared<SPLIT_TASK_TYPE>();
}

TaskManager::~TaskManager(){
    c_is_run = false;
}
//保存协议规则关联信息
//状态不佳时所写，此处需要优化
int TaskManager::save_relate_info(std::shared_ptr<CConfigManager> cm){
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return -1;
    }
    //std::unordered_map<接口地址, std::unordered_map<规则id, std::unordered_map<任务id, std::unordered_map<设备id, std::unordered_map<任务项id, int>>>>>
    c_tasks->clear();
    for(auto item = cm->get_items()->begin(); item != cm->get_items()->end(); item++){  //任务项
        
        T_TERMINAL_DEVICE_TYPE::iterator dev_it = cm->get_terminal_devices()->find(item->second.terminal_dev_id);
        if(dev_it != cm->get_terminal_devices()->end()){

            //保存接口信息
            auto i_it = c_interfaces.find(dev_it->second.channel);
            if(i_it == c_interfaces.end()){
                c_interfaces.insert(make_pair(dev_it->second.channel, dev_it->second.com_type));
            }
            int priority = 9;
            auto task = cm->get_task(item->second.task_id);
            if(nullptr != task){
                priority = task->priority;
            }
            //
            SPLIT_TASK_TYPE::iterator st_it = c_tasks->find(item->second.task_id);
            if(st_it == c_tasks->end()){
                TASK_PARAMS param;
                param.dev_id   = item->second.terminal_dev_id;
                param.type     = TASK_TYPE(task->type);
                param.task_id  = item->second.task_id;
                param.req_id   = -1;
                param.cmd_source = CMD_FROM_CLOUD;
                param.priority = priority;
                
                if ((task->type == TASK_TYPE_COLLECT) || (task->type == TASK_TYPE_FROZEN_COLLECT)){
                    ITEM_PARAMS item_params;
                    item_params.item_id = item->second.id;
                    param.items.push_back(item_params);
                }else{
                    ITEM_PARAMS item_params;
                    item_params.item_id = item->second.task_item_id;
                    param.items.push_back(item_params);
                }
                std::unordered_map<int64_t, TASK_PARAMS> tmp_item;
                tmp_item.insert(make_pair(item->second.terminal_dev_id, param));            
                c_tasks->insert(make_pair(item->second.task_id, tmp_item));
            }else{
                std::unordered_map<int64_t, TASK_PARAMS>::iterator dr_it = st_it->second.find(item->second.terminal_dev_id);
                if(dr_it == st_it->second.end()){
                    TASK_PARAMS param;
                    param.dev_id   = item->second.terminal_dev_id;
                    param.type     = TASK_TYPE(task->type);
                    param.priority = priority;
					param.req_id   = -1;
                    param.cmd_source = CMD_FROM_CLOUD;
                    param.task_id  = item->second.task_id;
                    if ((task->type == TASK_TYPE_COLLECT) || (task->type == TASK_TYPE_FROZEN_COLLECT)){
                        ITEM_PARAMS item_params;
                        item_params.item_id = item->second.id;
                        param.items.push_back(item_params);
                    }else{
                        ITEM_PARAMS item_params;
                        item_params.item_id = item->second.task_item_id;
                        param.items.push_back(item_params);
                    }
                    st_it->second.insert(make_pair(item->second.terminal_dev_id, param));
                }else{
                    if ((task->type == TASK_TYPE_COLLECT) || (task->type == TASK_TYPE_FROZEN_COLLECT)){
                        ITEM_PARAMS item_params;
                        item_params.item_id = item->second.id;
                        dr_it->second.items.push_back(item_params);
                    }else{
                        ITEM_PARAMS item_params;
                        item_params.item_id = item->second.task_item_id;
                        dr_it->second.items.push_back(item_params);
                    }
                    
                }
            }
        }
    }
    return 0;
}
//
void TaskManager::stop_task(){
    //等待处理线程结束
    for(auto v_if = c_htms.begin(); v_if != c_htms.end(); v_if++){
        v_if->second->stop();
    }
    c_htms.clear();
    //等待任务线程结束
    for(auto ttm = c_ttms.begin(); ttm != c_ttms.end(); ttm++){
        (*ttm)->stop();
    }
    c_ttms.clear();
}
//
std::shared_ptr<HandleThreadManager> TaskManager::generate_handle_thread(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm, std::string addr, int comm_type){
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return nullptr;
    }
    std::shared_ptr<HandleThreadManager> htm = std::make_shared<HandleThreadManager>(cm, mm, addr,comm_type);
    if(0 == htm->execute()){
        c_htms.insert(make_pair(addr, htm));
    }
    return htm;
}
/**
 * @brief 根据串口数量启动处理线程
 * 
 * @param cm 
 */
void TaskManager::assign_interfaces(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm){
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return ;
    }
    //处理接口列表
    for(auto if_it = c_interfaces.begin(); if_it != c_interfaces.end(); if_it++){
        auto find_htm = c_htms.find(if_it->first);
        if(find_htm == c_htms.end()){
            generate_handle_thread(cm, mm, if_it->first,if_it->second);
        }
    }
}
//
int TaskManager::assign_task(std::shared_ptr<CConfigManager> cm){
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return -1;
    }
    //处理任务列表
    for(auto t_it = c_tasks->begin(); t_it != c_tasks->end(); t_it++){
        //启动线程处理任务
        std::shared_ptr<TaskThreadManager> ttm = std::make_shared<TaskThreadManager>(cm, c_htms);
        ttm->execute(t_it->second);
        c_ttms.push_back(ttm);
    }
    return 0;
}

void run_action(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm, TaskManager* tm){
    if(nullptr == cm || nullptr == mm || NULL == tm){
        return ;
    }
    auto scene = cm->get_scene(cm->c_scene_id);
    if (nullptr == scene){
        return ;
    }
    for(auto action = scene->actions.begin(); action != scene->actions.end(); action++){
        millisecond_sleep(action->delay);
        ITEM_PARAMS  item;
        item.value = action->value;
        item.item_id = action->cmd_id;
        std::list<ITEM_PARAMS> items;
        items.push_back(item);
        TASK_PARAMS_INIT(action->device_id,-1,-1,2,"","",TASK_TYPE_LINKAGE,CMD_FROM_UNKNOWN,items);
        tm->run_cmd(cm, mm, param);
    }
}

int TaskManager::run_scene(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm){
    std::thread action_thread(run_action, cm, mm, this);
    action_thread.detach();
    
    return 0;
}
//
int TaskManager::run_task(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm){
    std::lock_guard<std::mutex> lock(c_run_mutex);
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return -1;
    }

    if((nullptr == cm->get_items()) || (cm->get_items()->empty())){
        CLogger::getInstance()->LOG_W("no task.");
        return -1;
    }
    //
    save_relate_info(cm);
    //
    stop_task();
    //
    assign_interfaces(cm, mm);
    //
    assign_task(cm);
    //执行场景动作
    run_scene(cm, mm);

    return 0;
}
//暂时无用
void TaskManager::change_uart_mode(){
    c_is_change_uart_mode = true;
}
//
void TaskManager::run_cmd(std::shared_ptr<CConfigManager> cm, std::shared_ptr<CMosquittoManager> mm, TASK_PARAMS &param){
    if(nullptr == cm){
        CLogger::getInstance()->LOG_W("no config info.");
        return ;
    }
    auto device = cm->get_terminal_device(param.dev_id);
    if(nullptr == device){
        return ;
    }

    auto find_htm = c_htms.find(device->channel);
    std::shared_ptr<HandleThreadManager> htm = nullptr;
    if(find_htm == c_htms.end()){
        htm = generate_handle_thread(cm, mm, device->channel,device->com_type);
    } else {
        htm = find_htm->second;
    }    
    if(nullptr != htm){
        htm->add_cmd_task_items(param);
    }
    
    char  cmdinfo[512] ={0};
    char  itminfo[128] ={0};
    for(auto itm= param.items.begin();itm != param.items.end(); itm++){
        snprintf(itminfo,sizeof(itminfo),"item_id=%lld,val=%s  ",itm->item_id,itm->value.c_str());    
        if(strlen(cmdinfo) >= sizeof(cmdinfo) -1){
            break;
        }
        strcat(cmdinfo,itminfo);
    }
    CLogger::getInstance()->LOG_I("run_cmd:devid=%lld,item:%s",param.dev_id, cmdinfo);
}